package com.baayso.bms2.config.spring;

import javax.inject.Inject;

import org.slf4j.Logger;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import com.baayso.bms2.core.log.Log;

import redis.clients.jedis.JedisPoolConfig;

/**
 * 缓存配置。
 * 
 * @author ChenFangjie(2015年9月19日 下午9:28:55)
 * 
 * @since 1.0.0
 * 
 * @version 1.0.0
 * 
 */
@Configuration
@EnableCaching // <!-- 启用缓存注解 --> <cache:annotation-driven cache-manager="cacheManager" />
@PropertySource("classpath:redis.properties") // 加载资源文件
public class CachingConfig {

    private static final Logger log = Log.get();

    @Inject
    private Environment env;

    // @Value("${redis.pool.maxTotal}")
    // private int redisPoolMaxTotal; // 最大分配的对象数
    //
    // @Value("${redis.pool.maxIdle}")
    // private int redisPoolMaxIdle; // 最大能够保持idel状态的对象数
    //
    // @Value("${redis.pool.maxWaitMillis}")
    // private long redisPoolMaxWaitMillis; // 当池内没有返回对象时，最大等待时间
    //
    // @Value("${redis.pool.testOnBorrow}")
    // private boolean redisPoolTestOnBorrow; // 当调用borrow Object方法时，是否进行有效性检查
    //
    // @Value("${redis.ip}")
    // private String redisIp;
    //
    // @Value("${redis.port}")
    // private int redisPort;
    //
    // @Value("${redis.password}")
    // private String redisPassword;

    // redis序列化策略 ，通常情况下key值采用String序列化策略
    // 如果不指定序列化策略，StringRedisTemplate的key和value都将采用String序列化策略
    // 但是RedisTemplate的key和value都将采用JDK序列化，这样就会出现采用不同template保存的数据不能用同一个template删除的问题

    @Bean
    public StringRedisSerializer stringRedisSerializer() {
        return new StringRedisSerializer();
    }

    @Bean
    public JedisPoolConfig jedisPoolConfig() {
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxTotal(this.env.getProperty("redis.pool.maxTotal", Integer.class, 1024));
        poolConfig.setMaxIdle(this.env.getProperty("redis.pool.maxIdle", Integer.class, 200));
        poolConfig.setMaxWaitMillis(this.env.getProperty("redis.pool.maxWaitMillis", Integer.class, 2000));
        poolConfig.setTestOnBorrow(this.env.getProperty("redis.pool.testOnBorrow", Boolean.class, true));
        // poolConfig.setMaxIdle(this.redisPoolMaxIdle);
        // poolConfig.setMaxWaitMillis(this.redisPoolMaxWaitMillis);
        // poolConfig.setTestOnBorrow(this.redisPoolTestOnBorrow);

        return poolConfig;
    }

    @Bean
    public JedisConnectionFactory jedisConnectionFactory() {
        JedisConnectionFactory factory = new JedisConnectionFactory();
        factory.setHostName(this.env.getProperty("redis.ip", "127.0.0.1"));
        factory.setPort(this.env.getProperty("redis.port", Integer.class, 6379));
        factory.setPassword(this.env.getProperty("redis.password", ""));
        // factory.setHostName(this.redisIp);
        // factory.setPort(this.redisPort);
        // factory.setPassword(this.redisPassword);
        factory.setPoolConfig(this.jedisPoolConfig());

        return factory;
    }

    @Bean
    public JdkSerializationRedisSerializer jdkSerializationRedisSerializer() {
        return new JdkSerializationRedisSerializer();
    }

    @Bean
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public RedisTemplate redisTemplate() {
        RedisTemplate template = new RedisTemplate();
        template.setConnectionFactory(this.jedisConnectionFactory());
        template.setKeySerializer(this.stringRedisSerializer());
        template.setHashKeySerializer(this.stringRedisSerializer());
        template.setValueSerializer(this.jdkSerializationRedisSerializer());

        return template;
    }

    @Bean
    public StringRedisTemplate stringRedisTemplate() {
        return new StringRedisTemplate(this.jedisConnectionFactory());
    }

    /** redisCacheManager用于spring缓存，redisCached为redis的工具类，用于业务的缓存。基于redis分布的session共享也是基于这个redisCached */
    @Bean
    public RedisCacheManager redisCacheManager() {
        log.info("RedisCacheManager");

        return new RedisCacheManager(this.redisTemplate());
    }

}
